/********************************************************************
	created:	30:9:2007   17:42
	author:		tiamo
	purpose:	create close
*********************************************************************/

#include "stdafx.h"

// create complete
NTSTATUS AppleKeyboardCreateComplete(__in PDEVICE_OBJECT pDeviceObject,__in PIRP pIrp,__in PVOID pContext)
{
	if(pIrp->PendingReturned)
		IoMarkIrpPending(pIrp);

	KeSetEvent(static_cast<PKEVENT>(pContext),IO_NO_INCREMENT,FALSE);

	return STATUS_MORE_PROCESSING_REQUIRED;
}

// create
NTSTATUS AppleKeyboardCreate(__in PDEVICE_OBJECT pDeviceObject,__in PIRP pIrp)
{
	NTSTATUS statusRet = STATUS_SUCCESS;
	BOOLEAN bReleaseFastMutex = FALSE;
	BOOLEAN bReleaseRemoveLock = FALSE;
	CDeviceExtension* pDevExt = static_cast<CDeviceExtension*>(pDeviceObject->DeviceExtension);

	AppleDebugPrint(DBGLEVEL_INFO,"Enter AppleKeyboardCreate %p,%p\n",pDeviceObject,pIrp);

	__try
	{
		PIO_STACK_LOCATION pIoStack = IoGetCurrentIrpStackLocation(pIrp);
		if(pIoStack->FileObject->FileName.Length)
		{
			AppleDebugPrint(DBGLEVEL_ERROR,"ERROR: Create AppleKeyboard Access Denied\n");
			statusRet = STATUS_ACCESS_DENIED;
			__leave;
		}

		statusRet = IoAcquireRemoveLock(&pDevExt->m_removeLock,pIrp);
		bReleaseRemoveLock = TRUE;
		if(!NT_SUCCESS(statusRet))
		{
			AppleDebugPrint(DBGLEVEL_ERROR,"ERROR: AppleKeyboard Unable to acquire remove lock\n");
			__leave;
		}

		ExAcquireFastMutex(&pDevExt->m_fastMutex);
		bReleaseFastMutex = TRUE;
		if(!pDevExt->m_dataConnect.ClassService)
		{
			AppleDebugPrint(DBGLEVEL_ERROR,"ERROR: Enable AppleKeyboard before connect\n");
			statusRet = STATUS_UNSUCCESSFUL;
			__leave;
		}

		IoCopyCurrentIrpStackLocationToNext(pIrp);
		pIoStack = IoGetCurrentIrpStackLocation(pIrp);
		KEVENT eventCreateComplete;
		KeInitializeEvent(&eventCreateComplete, NotificationEvent, FALSE);

		IoSetCompletionRoutine(pIrp,AppleKeyboardCreateComplete,&eventCreateComplete,TRUE,TRUE,TRUE);
		statusRet = IoCallDriver(pDevExt->m_pLowerDevice,pIrp);
		if(STATUS_PENDING == statusRet)
			KeWaitForSingleObject(&eventCreateComplete,Executive,KernelMode,FALSE,0);

		if(!NT_SUCCESS(statusRet))
			__leave;

		statusRet = pIrp->IoStatus.Status;

		if(!NT_SUCCESS(statusRet))
			__leave;

		InterlockedIncrement(&pDevExt->m_lEnableCount);

		if(!pDevExt->m_pReadFileObject && (pIoStack->Parameters.Create.SecurityContext->DesiredAccess & FILE_READ_DATA))
		{
			AppleDebugPrint(DBGLEVEL_INFO,"Enable AppleKeyboard\n");

			pDevExt->m_pReadFileObject = pIoStack->FileObject;
			KeResetEvent(&pDevExt->m_eventPingPongStopped);

			IoAcquireRemoveLock(&pDevExt->m_removeLock,pDevExt->m_pReadIrp);
			pDevExt->m_pReadIrp->IoStatus.Status = STATUS_SUCCESS;
			pDevExt->m_lReadState = READ_STATE_END;
			statusRet = AppleKeyboardStartRead(pDevExt);
			if(statusRet == STATUS_PENDING)
				statusRet = STATUS_SUCCESS;

			ASSERT(NT_SUCCESS(statusRet));
		}

		ASSERT(pDevExt->m_lEnableCount < 100 && pDevExt->m_lEnableCount > 0);
	}
	__finally
	{
		if(bReleaseFastMutex)
			ExReleaseFastMutex(&pDevExt->m_fastMutex);

		pIrp->IoStatus.Status = statusRet;
		pIrp->IoStatus.Information = 0;
		IoCompleteRequest(pIrp,IO_NO_INCREMENT);

		if(bReleaseRemoveLock)
			IoReleaseRemoveLock(&pDevExt->m_removeLock,pIrp);
	}

	AppleDebugPrint(DBGLEVEL_INFO,"Leave AppleKeyboardCreate 0x%08x\n",statusRet);

	return statusRet;
}

// close
NTSTATUS AppleKeyboardClose(__in PDEVICE_OBJECT pDeviceObject,__in PIRP pIrp)
{
	NTSTATUS statusRet = STATUS_SUCCESS;

	AppleDebugPrint(DBGLEVEL_INFO,"Enter AppleKeyboardClose %p,%p\n",pDeviceObject,pIrp);

	CDeviceExtension* pDevExt = static_cast<CDeviceExtension*>(pDeviceObject->DeviceExtension);

	ExAcquireFastMutex(&pDevExt->m_fastMutex);

	// dec enable count
	ASSERT(pDevExt->m_lEnableCount < 100 && pDevExt->m_lEnableCount > 0);
	if(!InterlockedDecrement(&pDevExt->m_lEnableCount))
	{
		AppleDebugPrint(DBGLEVEL_INFO,"Disable AppleKeyboard\n");
		KeWaitForSingleObject(&pDevExt->m_eventReadComplete,Executive,KernelMode,FALSE,0);
		IoCancelIrp(pDevExt->m_pReadIrp);
		KeWaitForSingleObject(&pDevExt->m_eventPingPongStopped,Executive,KernelMode,FALSE,0);

		ASSERT(pDevExt->m_pReadFileObject);
		KeCancelTimer(&pDevExt->m_timerRepeat);
		KeCancelTimer(&pDevExt->m_timerRecover);
		LARGE_INTEGER delayTime;
		delayTime.QuadPart = pDevExt->m_llTimeRepeatDelay.QuadPart;
		// because those two are all neg value,the smaller the longer
		if(delayTime.QuadPart> pDevExt->m_llTimeRecover.QuadPart)
			delayTime.QuadPart= pDevExt->m_llTimeRecover.QuadPart;

		delayTime.QuadPart *= 2;
		KeDelayExecutionThread(KernelMode,FALSE,&delayTime);
		pDevExt->m_pReadFileObject = 0;
	}

	ExReleaseFastMutex(&pDevExt->m_fastMutex);
	IoSkipCurrentIrpStackLocation(pIrp);
	statusRet = IoCallDriver(pDevExt->m_pLowerDevice,pIrp);

	AppleDebugPrint(DBGLEVEL_INFO,"Leave AppleKeyboardClose 0x%08x\n",statusRet);

	return statusRet;
}